package sm.hibernate.type;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

import org.apache.mina.core.buffer.IoBuffer;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;

import sm.codec.api.Codec;
import sm.codec.api.CodecFactory;
import sm.codec.exception.DecodeException;
import sm.codec.exception.EncodeException;
import sm.codec.type.NullValue;
import sm.codec.type.RC;
import sm.def.Type;

public abstract class AbstractRCPrimitiveType extends AbstractPrimitiveType {

	protected int getAllocateSize() {
		return 16;
	}

	protected Codec codec = CodecFactory.RC_CODEC;

	@Override
	public int[] sqlTypes() {
		return new int[] { Types.BINARY };
	}

	protected Object nullSafeGet(ResultSet rs, String[] names, Object owner,
			int type) throws HibernateException, SQLException {
		byte[] bytes = (byte[]) Hibernate.BINARY.nullSafeGet(rs, names, null,
				owner);
		Object value = null;
		if (bytes != null && bytes.length > 0) {
			IoBuffer buffer = IoBuffer.wrap(bytes);
			RC rc = null;
			try {
				rc = (RC) codec.decode(buffer);
			} catch (DecodeException e) {
				throw new HibernateException(e.getMessage(), e);
			}
			List<Object> values = rc.getValues();
			if (values != null && values.size() == 1) {
				value = values.get(0);
			} else {
				value = rc;
			}
		}

		if (value == null) {
			value = Type.getType(type).getNullValue();
		}

		return value;
	}

	protected void nullSafeSet(PreparedStatement st, Object value, int index,
			int type) throws HibernateException, SQLException {
		byte[] bytes = null;
		if (value != null && !(value instanceof NullValue)) {
			RC rc = null;
			if (value instanceof RC) {
				rc = (RC) value;
			} else {
				List<Object> values = new ArrayList<Object>();
				values.add(value);
				rc = new RC(values);
			}
			IoBuffer buffer = IoBuffer.allocate(getAllocateSize());
			buffer.setAutoExpand(true);
			try {
				codec.encode(buffer, rc);
			} catch (EncodeException e) {
				throw new HibernateException(e.getMessage(), e);
			}
			buffer.flip();
			bytes = new byte[buffer.limit()];
			buffer.get(bytes);
		}

		Hibernate.BINARY.nullSafeSet(st, bytes, index);
	}
}
